import { LRUCache } from '../../core/utils'
import _jwt from './_jwt'

function verificationLogin(paths: (RegExp | string)[], url: string) {
  if (paths) {
    return paths.some((p: RegExp | string) => {
      return (typeof p === 'string' && p === url) || (p instanceof RegExp && !!p.exec(url))
    })
  }

  return false
}
export const verify = _jwt.verify
export const sign = _jwt.sign
const lruCache = new LRUCache(1000)
export function jwt({ secret, unless = [], authDoc = true } = {} as { secret: string, unless: (RegExp | string)[], authDoc?: boolean }) {
  return function (ctx: any, next: any) {
    const paths = !unless || Array.isArray(unless)
      ? unless
      : [unless]
    authDoc && paths.push(/^\/__doc__/)
    /* 检验登录失败 */
    if (verificationLogin(paths, ctx.request.path)) { // 如果需要登录的接口要校验token
      return next()
    }

    const { Authorization, authorization } = ctx.request.headers
    const authToken = Authorization || authorization
    if (authToken) {
      const cacheData = lruCache.get(authToken)
      if (cacheData && Date.now() < cacheData.exp) {
        ctx.state.userInfo = ctx.state.user = cacheData
        return next()
      }
      try {
        const userInfo = _jwt.verify(authToken, secret)
        lruCache.set(authToken, userInfo)
        ctx.state.userInfo = ctx.state.user = userInfo
        return next()
      }
      catch (e: any) {
        ctx.throw(401, e && e.message)
      }
    }
    else {
      ctx.throw(401, '未发现token')
    }
  }
}
